#ifndef __PPMC_H__
#define __PPMC_H__

#include <string>
#include <iostream>
#include "Modelo.h"
#include "Contexto.h"
#include "../Aritmetico/ICompresor.h"

class PPMC
{

    private:
    
    std::istream *entrada;
    std::ostream *salida;
    
    ModeloMenosUno modeloMenosUno;
    Contexto contexto;
    ICompresor *compresorAritmetico;

    unsigned long posicionActualEnArchivo;

    static PPMC *instance;

    /**
    * Comprime el simbolo pasado.
    */
    void comprimirSimbolo(const Simbolo simbolo);
    
    /**
    * Descomprime un simbolo.
    */
    Simbolo descomprimirSimbolo();

    /**
     * @param orden Orden máximo de contexto.
     * @param compresorAritmetico Compresor aritmetico a utilizar. this se encarga
     * de destruirlo.
     */
    PPMC(Contexto::Orden orden=4,ICompresor *compresorAritmetico=NULL,
		Modelo *modeloCero=NULL);

    /**
     * Inicializa la entrada y la salida en this.
     */
    void inicializarEntradaSalida(std::istream &entrada,std::ostream &salida);

    public:

    virtual ~PPMC();

    /**
     * Borra la instancia existente en caso de corresponder y obtiene una nueva
     * instancia según los parámetros pasados.
     */
    static PPMC *getNewInstance(Contexto::Orden orden=4,
		ICompresor *compresorAritmetico=NULL,
		Modelo *modeloCero=NULL);

    /**
     * Libera recursos utilizados por la clase.
     */
    static void deleteInstance();

    /**
     * Obtiene la instancia.
     */
    static PPMC *getInstance();

    /**
     * Obtiene la posición actual del archivo en el que se encuentra leyendo.
     * Tener en cuenta que la posición está dada por el número de símbolo
     * que comprime/descomprime.
     */
    unsigned long getPosicionActualEnArchivo();
    
    /**
    * @pre entrada y salida deben estar abiertos para leer y escribir 
    * respectivamente.
    * Se comprime la entrada y se genera la salida en salida.
    */
    void comprimir(std::istream &entrada,std::ostream &salida);
    
    /**
    * @pre entrada y salida deben estar abiertos para leer y escribir 
    * respectivamente.
    * Se descomprime la entrada y se genera la salida en salida.
    */
    void descomprimir(std::istream &entrada,std::ostream &salida);

};

#endif

